﻿using System.Collections.Concurrent;
using System.Reflection;
using System.Runtime.Loader;

namespace Sgr.EventBus
{
    /// <summary>
    /// 类型解析器
    /// </summary>
    public static class IntegrationEventTypes
    {
        private static readonly ConcurrentDictionary<string, Type> _typeCache = new(StringComparer.Ordinal);

        /// <summary>
        /// 解析类型名称
        /// </summary>
        public static string ResolveTypeName<T>() => ResolveTypeName(typeof(T));

        /// <summary>
        /// 解析类型名称
        /// </summary>
        public static string ResolveTypeName(Type type)
        {
            var attr = type.GetCustomAttribute<IntegrationEventAttribute>();
            return attr?.ContractName ?? GetTypeCustomName(type);
        }

        /// <summary>
        /// 注册类型
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="type"></param>
        public static void RegisterType(string typeName, Type type)
        {
            if (string.IsNullOrWhiteSpace(typeName) || type == null) return;
            _typeCache.TryAdd(typeName, type);
        }

        /// <summary>
        /// 解析类型
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static Type? ResolveType(string typeName)
        {
            if (string.IsNullOrWhiteSpace(typeName))
                return null;

            // 先尝试缓存
            if (_typeCache.TryGetValue(typeName, out var cached) && cached != null)
                return cached;

            var resolved = ResolveTypeInternal(typeName);
            // 只有在成功解析到 Type 时才写缓存，避免保存 null
            if (resolved != null)
            {
                // 缓存到原始 key（生产者可能用了此格式）
                _typeCache.TryAdd(typeName, resolved);

                // 也缓存到标准化 key（FullName#Assembly），便于未来用另一种表示命中
                var canonical = GetTypeCustomName(resolved);
                if (!string.Equals(canonical, typeName, StringComparison.Ordinal))
                    _typeCache.TryAdd(canonical, resolved);
            }

            return resolved;
        }

        private static Type? ResolveTypeInternal(string typeName)
        {
            // 1. 直接尝试 Type.GetType（支持 assembly-qualified name）
            try
            {
                var t = Type.GetType(typeName, throwOnError: false, ignoreCase: false);
                if (t != null) return t;
            }
            catch { /* ignore */ }

            // 2. 遍历所有已加载的程序集
            string lookupTypeName = typeName;
            string assemblyName = string.Empty;
            if (typeName.Contains('#'))
            {
                var parts = typeName.Split('#', 2);
                lookupTypeName = parts[0];
                assemblyName = parts[1];
            }

            // 3. 在已加载的程序集列表中查找（优先按 assemblyName 过滤）
            var searchAssemblies = AssemblyLoadContext.Default?.Assemblies ?? AppDomain.CurrentDomain.GetAssemblies();
            if (!string.IsNullOrWhiteSpace(assemblyName))
            {
                searchAssemblies = searchAssemblies.Where(a =>
                    string.Equals(a.GetName().Name, assemblyName, StringComparison.OrdinalIgnoreCase) ||
                    string.Equals(a.FullName, assemblyName, StringComparison.OrdinalIgnoreCase));
            }

            foreach (var asm in searchAssemblies)
            {
                Type[] types;
                try
                {
                    types = asm.GetTypes();
                }
                catch (ReflectionTypeLoadException ex)
                {
                    types = ex.Types.Where(x => x != null).ToArray()!;
                }
                catch
                {
                    continue;
                }

                foreach (var ty in types)
                {
                    if (ty == null) continue;
                    if (!typeof(IntegrationEvent).IsAssignableFrom(ty)) continue;

                    try
                    {
                        // match FullName or Name (case-sensitive FullName comparison is safer)
                        var full = ty.FullName ?? ty.Name;
                        if (string.Equals(full, lookupTypeName, StringComparison.Ordinal))
                            return ty;

                        var attr = ty.GetCustomAttribute<IntegrationEventAttribute>();
                        if (attr != null && !string.IsNullOrWhiteSpace(attr.ContractName) &&
                            string.Equals(attr.ContractName, typeName, StringComparison.Ordinal))
                        {
                            return ty;
                        }

                        // contract name might match lookupTypeName as well
                        if (attr != null && !string.IsNullOrWhiteSpace(attr.ContractName) &&
                            string.Equals(attr.ContractName, lookupTypeName, StringComparison.Ordinal))
                        {
                            return ty;
                        }
                    }
                    catch { /* ignore attribute read errors */ }
                }
            }

            // 已放弃按短名(Name)的兜底搜索（避免冲突）
            return null;
        }

        /// <summary>
        /// 获取类型自定义名称
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static string GetTypeCustomName(Type type)
        {
            return $"{type.FullName ?? type.Name}#{type.Assembly.GetName().Name}";
        }
    }
}